home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d16
/
wsmooth.arc
/
WSMSRC.ARC
/
FILEBUF.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-09
|
13KB
|
453 lines
// filebuf.c RHS 9/1/90 file-buffering and handling routines
#ifdef WINDOWS
#include<windows.h>
#include"wsmooth.h"
#include"wsmooth2.h"
#endif
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<dos.h>
#include<fcntl.h>
#include<sys\types.h>
#include<sys\stat.h>
#include<io.h>
#include"filebuf.h"
#define TRUE 1
#define FALSE 0
#define MAXSCREEN 25
#define CTRL_Z 0x1A
#define CR '\r'
#define LF '\n'
#define MYEOF 0xffff
#define PAGEINDEXSIZE 50
#define HALFBUFFER (30*1024)
#define MAXFILESIZE ((long)PAGEINDEXSIZE*(long)HALFBUFFER)
#define BUFFERSIZE (HALFBUFFER*2)
#if defined(WINDOWS)
HANDLE indexbufhdl = NULL, bufferhdl = NULL;
extern HWND WinSmooth;
#endif
unsigned far *lineptr; // pointer to line index in index segment
unsigned far *pageptr; // pointer to page index in index segment
unsigned far *indexstart = NULL; // pointer to start of line index
unsigned far *indexbuf = NULL; // pointer to index buffer
char far *fileptr = NULL; // pointer to curr line
char far *bufstart = NULL; // pointer to start of filebuffer
char far *bufend; // point to end of buffer
int fh = -1;
int stripbits = FALSE;
void filebuf_updateindex(int endndx);
void filebuf_read(void);
void filebuf_nextbuffer(void);
void filebuf_prevbuffer(void);
void filebuf_reset(void);
void filebuf_stripbits(char far *buf, unsigned len);
void error_exit(int err, char *msg);
BOOL filebuf_fileisopen(void)
{
if(fh != -1)
return TRUE;
return FALSE;
}
// toggles bit stripping flag
void filebuf_strip(int strip)
{
stripbits = strip;
}
// strips high bit from bytes read
void filebuf_stripbits(char far *buf, unsigned len)
{
if(!stripbits)
return;
for( ; len; len--)
buf[len-1] &= 0x7f;
}
// initializes file buffers
int filebuf_init(void)
{
if(indexbufhdl && bufferhdl)
{
filebuf_reset();
return TRUE;
}
// allocate index buffer and file buffer
#ifdef WINDOWS
{
unsigned u = BUFFERSIZE+1; // use an unsigned to get over compiler bug
// allocate index and file buffers
if(indexbufhdl = GlobalAlloc(GMEM_MOVEABLE,u))
indexbuf = (unsigned far *)GlobalWire(indexbufhdl);
if(bufferhdl = GlobalAlloc(GMEM_MOVEABLE,u))
bufstart = (char far *)GlobalWire(bufferhdl);
if(!indexbufhdl || !bufferhdl)
{
Message(WinSmooth,"Unable to allocate memory buffers: hdls=%u,%u ptrs=%lp,%lp size=%ld",
indexbufhdl,bufferhdl,indexbuf,bufstart,GlobalSize(indexbufhdl));
return FALSE;
}
}
if(!indexbuf || !bufstart)
Message(WinSmooth,"Unable to re-locate memory buffers: ptrs=%lp,%lp",
indexbuf,bufstart);
#else
indexbuf = (unsigned far *)_fmalloc(BUFFERSIZE+1);
bufstart = (char far *)_fmalloc(BUFFERSIZE+1);
if(!indexbuf || !bufstart)
error_exit(0,"No buffer allocation");
#endif
// set line pointer to beginning of line index
indexstart = lineptr = &indexbuf[PAGEINDEXSIZE];
// set page pointer to beginning of page index
pageptr = indexbuf;
// initialize indexes
_fmemset(indexbuf,0x0000,BUFFERSIZE);
// set last word of line index to MYEOF
indexbuf[BUFFERSIZE/(sizeof(unsigned))] = MYEOF;
return TRUE;
}
// resets variables for new file without re-allocating buffers
void filebuf_reset(void)
{
lineptr = indexstart;
pageptr = indexbuf;
fileptr = NULL;
_fmemset(indexbuf,0x0000,BUFFERSIZE);
}
int filebuf_open(char *filename, int strip)
{
if(!(*filename))
return FALSE;
#ifdef WINDOWS
{
OFSTRUCT of;
// open the file for read only, and allow others to read it (but not write)
if((fh = OpenFile(filename,&of,
OF_CANCEL | OF_PROMPT | OF_READ | OF_SHARE_DENY_WRITE)) == -1)
{
Message(WinSmooth,"Error %d opening %s",of.nErrCode,filename);
return FALSE;
}
}
#else
if((fh = open(filename,O_BINARY | O_RDONLY)) == -1)
error_exit(0,"Unable to open file");
#endif
{
struct stat s;
if(fstat(fh,&s)) // get file size
return FALSE;
if(s.st_size > MAXFILESIZE) // check file size
#ifdef WINDOWS
{
Message(WinSmooth,"%s is too large to be handled by WinSmooth",
filename);
return FALSE;
}
#else
error_exit(0,"File too large");
#endif
}
filebuf_read(); // get first buffer from file
{
unsigned len; // read entire file
for(len = 1; filebuf_nextline(&len) && len; );
}
stripbits = (strip ? TRUE : FALSE);
return TRUE;
}
// de-allocates filebuffers and cleans up
void filebuf_destruct(void)
{
#if defined(WINDOWS)
if(indexbufhdl)
{
GlobalUnWire(indexbufhdl);
GlobalFree(indexbufhdl);
}
if(bufferhdl)
{
GlobalUnWire(bufferhdl);
GlobalFree(bufferhdl);
}
indexbufhdl = bufferhdl = NULL;
#else
if(indexbuf)
_ffree(indexbuf);
if(bufstart)
_ffree(bufstart);
bufstart = NULL;
indexbuf = NULL;
#endif
if(fh != -1)
close(fh);
fh = -1;
}
// reads buffer from file
void filebuf_read(void)
{
unsigned bytes;
lseek(fh,(HALFBUFFER*(pageptr-indexbuf)),SEEK_SET);
_dos_read(fh,&bufstart[HALFBUFFER],HALFBUFFER,&bytes);
filebuf_stripbits(&bufstart[HALFBUFFER],HALFBUFFER);
fileptr = (!fileptr ? &bufstart[HALFBUFFER] : (fileptr -= HALFBUFFER));
bufend = &bufstart[HALFBUFFER+bytes]; // set to end of buffer
*bufend = CTRL_Z;
filebuf_updateindex((bytes != HALFBUFFER) ? TRUE : FALSE);
}
// updates line index for buffer
void filebuf_updateindex(int endndx)
{
char far *buf = fileptr;
char far *old = fileptr;
unsigned far *ndx = lineptr;
unsigned numlines = ((pageptr == indexbuf) ? 0 : pageptr[-1]);
while(buf <= bufend) // until end of buffer
switch(*buf)
{
case CR: // if CR or LF found
case LF:
buf++; // check next character
if(*buf == LF) // if CR followed by line feed
buf++;
*ndx++ = (buf-old); // use ptr arithmetic to get length
numlines++;
old = buf; // set old to next line
if(buf == bufend)
buf++;
break; // break so as not to fall thru
case CTRL_Z:
bufend = buf; // CTRL_Z found, set new buf end
if(buf > old) // if line ends with CTRL_Z
*ndx++ = 0;
buf++;
break;
default:
buf++;
break;
}
*pageptr = numlines; // set to accumulated line count
if(endndx) // if end of file reached
*ndx = MYEOF; // set end of file marker in index
}
// read next buffer from file
void filebuf_nextbuffer(void)
{
// copy the 2nd half of buffer to the 1st half
_fmemcpy(bufstart,&bufstart[HALFBUFFER],HALFBUFFER);
pageptr++; // set for next page
// read HALFBUFFER bytes into 2nd half
filebuf_read();
}
// read previous buffer from file
void filebuf_prevbuffer(void)
{
if(pageptr == indexbuf) // insure we're not on 1st page
return;
// copy 1st buffer to 2nd
_fmemcpy(&bufstart[HALFBUFFER],bufstart,HALFBUFFER);
fileptr += HALFBUFFER; // adjust pointer to its position in 2nd page
pageptr--; // seek to page
lseek(fh,(HALFBUFFER*(pageptr-indexbuf)),SEEK_SET);
{
unsigned bytes;
_dos_read(fh,bufstart,HALFBUFFER,&bytes); // read the file into the 1st buffer
filebuf_stripbits(bufstart,HALFBUFFER);
}
bufend = &bufstart[BUFFERSIZE]; // set to end of buffer
*bufend = CTRL_Z;
}
// seek to a particular line
void filebuf_seekline(unsigned line)
{
unsigned far *page = indexbuf, far *buf1, far *buf2, far *ndx;
// find a page with a higher accum. line count
for( ; line > *page && *page; page++);
if(page == indexbuf) // if we're on the first page (no prev. page)
{
buf1 = page; // set for first 2 buffers
buf2 = page+1;
}
else if(*(page+1) == 0) // or not on 1st page and next page is empty
{
buf1 = page-1; // set for this and prev buffer
buf2 = page;
}
else // or we are between two real pages
{
if(line > (*(page-1) + ((*(page+1) - *(page-1)) / 2)))
{
buf1 = page;
buf2 = page+1;
}
else
{
buf1 = page-1;
buf2 = page;
}
}
lineptr = indexstart+line; // set lineptr to the line
pageptr = page; // set pageptr to the page
if(*buf2) // if no 2nd page, nothing to read
{
unsigned bytes;
// read 1st buffer
lseek(fh,(HALFBUFFER*(buf1-indexbuf)),SEEK_SET);
_dos_read(fh,bufstart,HALFBUFFER,&bytes);
lseek(fh,(HALFBUFFER*(buf2-indexbuf)),SEEK_SET);
_dos_read(fh,&bufstart[HALFBUFFER],HALFBUFFER,&bytes);
filebuf_stripbits(bufstart,HALFBUFFER*2);
bufend = &bufstart[HALFBUFFER+bytes]; // set to end of buffer
*bufend = CTRL_Z;
fileptr = (page == buf1) ? bufstart : &bufstart[HALFBUFFER];
}
else
fileptr = &bufstart[HALFBUFFER];
ndx = indexstart;
ndx += ((pageptr == indexbuf) ? 0 : *(pageptr-1));
if(*buf2)
if(fileptr != bufstart)
{
while(fileptr[-1] != CR && fileptr[-1] != LF)
fileptr--;
}
else if(lineptr != indexstart)
{
ndx++;
while(fileptr[1] != CR && fileptr[1] != LF)
fileptr++;
fileptr++;
while(*fileptr == CR || *fileptr == LF)
fileptr++;
}
for(; ndx < lineptr; fileptr += *ndx, ndx++)
;
}
// get next line from file
char far *filebuf_nextline(unsigned *len)
{
char far *linestart;
char far *bufptr; // local pointer
*len = 0;
if(*lineptr == MYEOF)
return NULL;
reset:
linestart = fileptr; // set linestart to fileptr
// read until buffer end encountered, or until CR found
for( bufptr = fileptr; bufptr != bufend; bufptr++)
if((*bufptr == CR) || (*bufptr == LF))
break;
if(bufptr == bufend) // end of buffer, line carries over
{
filebuf_nextbuffer(); // read more of file
goto reset;
}
*len = (bufptr-fileptr); // remove CR from buf
fileptr += *lineptr++;
return linestart;
}
// get previous line from file
char far *filebuf_prevline(unsigned *len)
{
char far *bufptr;
*len = 0;
if(lineptr == indexstart) // if at beginning of file
return NULL;
--lineptr; // set to previous line
bufptr = bufstart+HALFBUFFER;
if((fileptr > bufptr) && ((fileptr - *lineptr) <= bufptr))
pageptr--; // set to prev page
if((bufstart + *lineptr) > fileptr) // if line length extends from previous page
filebuf_prevbuffer();
fileptr -= (*lineptr);
for(bufptr = fileptr; bufptr != bufend; bufptr++)
if((*bufptr == CR) || (*bufptr == LF))
break;
*len = (bufptr - fileptr);
return fileptr;
}
// returns number of lines line file
unsigned filebuf_numlines(void)
{
unsigned far *page;
for(page = indexbuf; *(page+1); page++)
;
return *page;
}
// returns length of longest line in file
unsigned filebuf_longestline(void)
{
unsigned far *ndx = indexstart;
unsigned longest = 0;
for( ; *ndx != MYEOF; ndx++)
if(*ndx > longest)
longest = *ndx;
return longest;
}
// exit routine on fatal error
void error_exit(int err, char *msg)
{
#if defined(WINDOWS)
extern HWND WinSmooth;
Message(WinSmooth,msg);
#else
printf("%s\n",msg);
#endif
exit(err);
}